extern crate proc_macro;

use builtin_parse::BuiltinParser;
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::{parse_macro_input, LitStr, ItemFn};

mod builtin_parse;

/// This attribute will turn function to a struct and impl `to_builtin` method for it.
///
/// Support function args type:
/// - [`i32`]
/// - [`f32`]
/// - [`bool`]
/// - [`String`]
/// - `dj::Expr`
/// - `dj::Value`
/// - `Rc<dj::Env>`
/// - `Vec<Expr>`
/// - `&mut Vec<Expr>`
/// - [`Option<T>`]: `T` is impl `TryInto<T> for Value`, or `Option<Expr>`.
///   _Using `Option` will make the input of this parameter unnecessary and will affect the determination of the number of parameters_
/// 
/// These type may be supported
/// - [`Vec<Value>`]
/// - [`Hash<String, Value>`]
///
/// Don't need evaluate type are (don't contain `&mut Environment`):
/// - `Expr`
/// - [`Option<Expr>`]
/// - [`Vec<Expr>`]
/// 
/// Before use this attribute macro, need the code of `use` below:
/// ```rust
/// use dj::builtin::{builtin_method, dependency::*};
/// ```
#[proc_macro_attribute]
pub fn builtin_method(attr: TokenStream, input: TokenStream) -> TokenStream {
    let item_fn = parse_macro_input!(input as ItemFn);
    let name = if attr.is_empty() {
        None
    } else {
        Some(parse_macro_input!(attr as LitStr))
    };

    let parse = BuiltinParser::new(name, item_fn);

    parse.into_token_stream().into()
}